﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using TodoApp.EntityFrameworkCore.Core;

namespace TodoApp.EntityFrameworkCore
{
    public static class TodoAppEntityFrameworkCoreExtensions
    {
        public static IServiceCollection AddEntityFrameworkCore<TDbContext>(this IServiceCollection services, Action<DbContextOptionsBuilder> action)
            where TDbContext : DbContext
        {
            services.AddSingleton<IMyModelCustomizer, ModelSoftDeleteCustomizer>();

            services.AddTransient<IInterceptor,SoftDeleteInterceptor>();

            services.AddDbContext<TDbContext>((provider, options) =>
            {
                action?.Invoke(options);

                var interceptors = provider.GetServices<IInterceptor>();
                if (interceptors.Any())
                {
                    options.AddInterceptors(interceptors);
                }

                options.ReplaceService<IModelCustomizer, MyCustomizer>();
                options.UseApplicationServiceProvider(provider);
            });
            return services;
        }
    }


    public class SoftDeleteInterceptor : SaveChangesInterceptor
    {
        public override int SavedChanges(SaveChangesCompletedEventData eventData, int result)
        {
            SofeDelete(eventData.Context.ChangeTracker);
            return base.SavedChanges(eventData, result);
        }

        public override ValueTask<int> SavedChangesAsync(SaveChangesCompletedEventData eventData, int result, CancellationToken cancellationToken = default)
        {
            SofeDelete(eventData.Context.ChangeTracker);
            return base.SavedChangesAsync(eventData, result, cancellationToken);
        }


        private void SofeDelete(ChangeTracker changeTracker)
        {
            foreach (var entry in changeTracker.Entries().Where(x => x.Entity is ISoftDelete && (x.State == EntityState.Deleted)))
            {
                entry.State = EntityState.Modified;
                if (entry.Entity is ISoftDelete softDeleteEntity)
                {
                    softDeleteEntity.IsDeleted = true;
                }
            }
        }
    }
}